package com.qudian.pay.log.aop;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.service.EchoService;
import com.alibaba.dubbo.rpc.service.GenericService;
import com.alibaba.fastjson.JSON;
import com.qudian.pay.core.aop.BaseInterceptor;
import com.qudian.pay.core.diagnostic.Profiler;
import com.qudian.pay.core.runtime.MdcHolder;
import com.qudian.pay.core.runtime.ProductContext;
import com.qudian.pay.core.runtime.ProductContextHolder;
import com.qudian.pay.core.runtime.ProductEnvironment;
import com.qudian.pay.core.utils.IPUtils;

/**
 * @Description: Service代理,用于处理环境数据
 * @ClassName: ServiceContextInitInterceptor
 * @author gaoxiang
 * @date 2016年5月24日 下午3:39:54
 */ 
public class ServiceContextInitInterceptor extends BaseInterceptor {
	
	private final static Logger logger = LoggerFactory.getLogger(ServiceContextInitInterceptor.class);
	
	@Override
	public Object bizInvoke(MethodInvocation invocation) throws Throwable {
		try {
			//如果是本地业务请求RPC Service则将本地上下文数据传递给远程
			if (isLocalProxy(invocation)) {
				pullContext(invocation);
			} else {
				pushContext(invocation);
			}
			// 设置MDC
			MdcHolder.init(ProductContextHolder.getProductContext());
			return invocation.proceed();
		} finally {
		}
	}
	
	/**
	 * @Description: 判断是远程Service还是本地Service(依赖dubbo)
	 * @param invocation
	 * @return boolean 返回类型
	 * @author gaoxiang
	 * @date 2016年5月24日 下午4:27:53
	 */
	private boolean isLocalProxy(MethodInvocation invocation) {
		if ((invocation.getThis() instanceof EchoService) || (invocation.getThis() instanceof GenericService)) {
			return false;
		} else {
			return true;
		}
	}
	
	/**
	 * @Description: 拉取环境上下文数据
	 * @param invocation
	 * @return void 返回类型
	 * @author gaoxiang
	 * @date 2016年5月24日 下午4:27:53
	 */
	private void pullContext(MethodInvocation invocation) {
		if (Profiler.isSuperStart() && MdcHolder.unInit()) {
			logger.debug("web app invoke local service:" + ToStringBuilder.reflectionToString(invocation.getThis()));
		} else {
			// 获得当前被调用的参数,准备ProductContext[从dubbo服务中获取]
			String productContextStr = RpcContext.getContext().getAttachment(String.valueOf(ProductContext.class.getName().hashCode()));
			if (StringUtils.isNotBlank(productContextStr)) {
				ProductContext productContext = JSON.parseObject(productContextStr, ProductContext.class);
				ProductEnvironment environment = productContext.getEnvironment();
				environment.setClientIp(environment.getServerIp());
				environment.setServerIp(IPUtils.getIp4Single());
				environment.setServerName(RpcContext.getContext().getRemoteHostName());
				ProductContextHolder.setProductContext(productContext);
			}
		}
	}
	
	/**
	 * @Description: 推送环境上下文数据
	 * @param invocation
	 * @return void 返回类型
	 * @author gaoxiang
	 * @date 2016年5月24日 下午4:28:47
	 */
	private void pushContext(MethodInvocation invocation) {
		ProductContext productContext = ProductContextHolder.getProductContext();
		ProductEnvironment environment = productContext.getEnvironment();
		if (StringUtils.isBlank(environment.getServerIp())) environment.setServerIp(IPUtils.getIp4Single());
		if (StringUtils.isBlank(environment.getServerName())) environment.setServerName(RpcContext.getContext().getRemoteHostName());
		String productContextInfo = JSON.toJSONString(productContext);
		RpcContext.getContext().setAttachment(String.valueOf(ProductContext.class.getName().hashCode()), productContextInfo);
	}
}
